using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using Tomahawk.Runtime.Input;

namespace Tomahawk.Runtime.Screen.Controls
{
    /// <summary>
    /// This class represent a form of the game menu
    /// </summary>
    public class Form : ScreenControl
    {
        #region "Game Pad State List"

        List<GamePadManager> gamePadManagers;
        List<GamePadState> gamePadPreviousState; //I need a copy of the previous state of every pad
        KeyboardState keyboardPreviousState;    //I need a copy of the previous state of the keyboard

        /// <summary>
        /// Set the gamepadstates that will be handling the form
        /// </summary>
        public void SetGamePadManagers(GamePadManager[] padManagers)
        {
            gamePadManagers.Clear();
            gamePadPreviousState.Clear();
            foreach (GamePadManager padManager in padManagers)
            {
                gamePadManagers.Add(padManager);
                gamePadPreviousState.Add(new GamePadState());
            }
        }

        #endregion

        #region "Notification to parent / containers "

        public delegate void FormNotificationDelegate(string Message);

        /// <summary>
        /// Handle this to receive notifications from this control
        /// </summary>
        public event FormNotificationDelegate OnNotification;

        /// <summary>
        /// Call this from your derived class to invoke the OnNotification event
        /// </summary>
        protected void Notify(string Message)
        {
            if (OnNotification!=null) this.OnNotification(Message);
        }

        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        public Form()
        {
            //create the gamepadstate list, and set the first player as the default controller
            gamePadManagers = new List<GamePadManager>();
            gamePadManagers.Add(Engine.Instance.InputManager.Pads.PlayerOne);

            gamePadPreviousState = new List<GamePadState>();
            gamePadPreviousState.Add(new GamePadState());
            //gamePadManagers.Add(Engine.Instance.InputManager.Pads.PlayerTwo); //The second player also can move in gui

            //invoke the initialization
            this.OnInitialize();
        }

        /// <summary>
        /// Override this to provide initialization logic
        /// </summary>
        protected virtual void OnInitialize()
        {
        }

        /// <summary>
        /// Override this to provide per-frame update logic 
        /// </summary>
        protected virtual void OnUpdate(float elapsedTime)
        {
        }

        /// <summary>
        /// Override this to provide rendering logic
        /// </summary>
        protected override void OnRender(GraphicsDevice device, SpriteBatch spriteBatch)
        {
        }

        /// <summary>
        /// Override this to provide assets loading logic
        /// </summary>
        protected override void OnLoadGraphicContent(GraphicsDevice myDevice, ContentManager myLoader)
        {
        }

        #region "Key Event Handling"

        /// <summary>
        /// Manage input on update
        /// </summary>
        private void processInput(GamePadState padState, GamePadState padStatePrevious)
        {
            if(padState.PacketNumber == padStatePrevious.PacketNumber){
                return;
            }

            //Ok
            if (padState.Buttons.A == ButtonState.Pressed && padStatePrevious.Buttons.A == ButtonState.Released)
            {
                this.OnKeyPress(FormKeys.Ok);
                return;
            }

            //Cancel
            if (padState.Buttons.B == ButtonState.Pressed && padStatePrevious.Buttons.B == ButtonState.Released)
            {
                this.OnKeyPress(FormKeys.Cancel);
                return;
            }

            //Left
            if (padState.DPad.Left == ButtonState.Pressed && padStatePrevious.DPad.Left == ButtonState.Released)
            {
                this.OnKeyPress(FormKeys.Left);
                return;
            }

            //Right
            if (padState.DPad.Right == ButtonState.Pressed && padStatePrevious.DPad.Right== ButtonState.Released)
            {
                this.OnKeyPress(FormKeys.Right);
                return;
            }

            //Up
            if (padState.DPad.Up == ButtonState.Pressed && padStatePrevious.DPad.Up == ButtonState.Released)
            {
                this.OnKeyPress(FormKeys.Up);
                return;
            }

            //Down
            if (padState.DPad.Down == ButtonState.Pressed && padStatePrevious.DPad.Down == ButtonState.Released)
            {
                this.OnKeyPress(FormKeys.Down);
                return;
            }
            
            //Thumbstick
            if (padState.ThumbSticks.Left.X > 0.85 && padStatePrevious.ThumbSticks.Left.X < 0.85)
            {
                this.OnKeyPress(FormKeys.Right);
            }
            if (padState.ThumbSticks.Left.X < -0.85 && padStatePrevious.ThumbSticks.Left.X > -0.85 )
            {
                this.OnKeyPress(FormKeys.Left);
            }
            if (padState.ThumbSticks.Left.Y > 0.85 && padStatePrevious.ThumbSticks.Left.Y < 0.85)
            {
                this.OnKeyPress(FormKeys.Up);
            }
            if (padState.ThumbSticks.Left.Y < -0.85 && padStatePrevious.ThumbSticks.Left.Y > -0.85)
            {
                this.OnKeyPress(FormKeys.Down);
            }
            
        }

        /// <summary>
        /// DEBUG Util: Handle input from keyboard
        /// </summary>
        private void processKeyboard(KeyboardState currentState, KeyboardState previousState)
        {
            //Ok
            if ( (currentState.IsKeyDown(Keys.Enter) && previousState.IsKeyUp(Keys.Enter)) ||
                (currentState.IsKeyDown(Keys.A) && previousState.IsKeyUp(Keys.A))
               )
            {
                this.OnKeyPress(FormKeys.Ok);
            }

            //Cancel
            if ( (currentState.IsKeyDown(Keys.Escape) && previousState.IsKeyUp(Keys.Escape)) ||
                (currentState.IsKeyDown(Keys.B) && previousState.IsKeyUp(Keys.B))
               )
            {
                this.OnKeyPress(FormKeys.Cancel);
            }

            //Left
            if (currentState.IsKeyDown(Keys.Left) && previousState.IsKeyUp(Keys.Left))
            {
                this.OnKeyPress(FormKeys.Left);
            }

            //Right
            if (currentState.IsKeyDown(Keys.Right) && previousState.IsKeyUp(Keys.Right))
            {
                this.OnKeyPress(FormKeys.Right);
            }

            //Up
            if (currentState.IsKeyDown(Keys.Up) && previousState.IsKeyUp(Keys.Up))
            {
                this.OnKeyPress(FormKeys.Up);
            }

            //Down
            if (currentState.IsKeyDown(Keys.Down) && previousState.IsKeyUp(Keys.Down))
            {
                this.OnKeyPress(FormKeys.Down);
            }
        }

        /// <summary>
        /// Possible key commands on forms
        /// </summary>
        public enum FormKeys
        {
            Left,
            Right,
            Up,
            Down,
            Ok,
            Cancel
        }

        /// <summary>
        /// Override this to provide input handling
        /// </summary>
        public virtual void OnKeyPress(FormKeys key)
        {
        }

        #endregion

        /// <summary>
        /// Used to do per frame stuff
        /// </summary>
        public void Update(float elapsedTime)
        {
            for(int i = 0; i < gamePadManagers.Count; i++)
                processInput(gamePadManagers[i].State, gamePadPreviousState[i]);
            
            this.processKeyboard(Keyboard.GetState(), keyboardPreviousState);

            //call the update method
            this.OnUpdate(elapsedTime);

            #region Store the current state in the variable that stores the previous
            //store in the previous the current state
            for (int i = 0; i < gamePadPreviousState.Count; i++)
                gamePadPreviousState[i] = gamePadManagers[i].State; //The state returns a copy of the state, not a reference (just needed)

            keyboardPreviousState = Keyboard.GetState();
            #endregion
        }

    }

}


